# Create your views here.
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.http import Http404
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404

from django import forms
from django.forms import ModelForm

from cuestionarios.models import Cuestionario

from cuestionarios.models import EBF
from cuestionarios.models import Negacion
from cuestionarios.models import VariableLibre
from cuestionarios.models import OperacionNaria

from cuestionarios.models import ElementoDeCuestionario
from cuestionarios.models import Pregunta
from cuestionarios.models import GrupoDePreguntas
from cuestionarios.models import Opcion
from cuestionarios.models import GrupoDeOpciones
from cuestionarios.models import CampoBoolVolatil

from usuarios.views import index
from gestion_cuestionarios.views import view_lista_cuestionarios

from django.db.models import Max

import re




class CuestionarioForm(ModelForm):
    class Meta:
        model = Cuestionario
        fields = ('nombre', 'descripcion')

def view_cuestionario(request, cuest_id):
    #FORMULARIO DEL CUESTIONARIO
    try:
        cuestionario = Cuestionario.objects.get(pk=int(cuest_id))
    except Cuestionario.DoesNotExist:
        raise Http404
    if request.method == 'POST':
        form = CuestionarioForm(request.POST, instance=cuestionario)
        if form.is_valid():
            form.save()
    form = CuestionarioForm(instance = cuestionario)
    
    #LISTA DE PREGUNTAS
    preguntas = Pregunta.objects.filter(cuestionario = cuestionario.pk).order_by('numero')

    contexto = {'form':form, 'preguntas':preguntas, 'cuestionario':cuestionario, 'breadcrumbs': breadcrumbs(cuestionario)}
    contexto.update(csrf(request))
    return render_to_response(r'edicion_hipertextual/cuestionario_edicion_hipertextual.html', contexto)

######################PREGUNTA#######################

class PreguntaForm(ModelForm):
    class Meta:
        model = Pregunta
        fields = ('nombre','texto')
        
def view_elementodecuestionario(request,elem_id):
    elem = ElementoDeCuestionario.objects.get(pk=elem_id).getSubTipo()
    if isinstance(elem,Pregunta):
        return view_pregunta(request,elem_id)
    if isinstance(elem,Opcion):
        return view_opcion(request, elem_id)

def view_pregunta(request, preg_id):
    try:
        pregunta = Pregunta.objects.get(pk=int(preg_id))
    except Pregunta.DoesNotExist:
        raise Http404
    if request.method == 'POST':
        form = PreguntaForm(request.POST, instance=pregunta)
        if form.is_valid():
            form.save()
    form = PreguntaForm(instance = pregunta)
    #LISTA DE OPCIONES
    opciones = Opcion.objects.filter(pregunta=pregunta.pk)

    contexto = {'form':form, 'opciones':opciones,'pregunta':pregunta, 'breadcrumbs': breadcrumbs(pregunta), 'reglapreview': previewRegla(pregunta.regla)}
    contexto.update(csrf(request))
    return render_to_response(r'edicion_hipertextual/pregunta_edicion_hipertextual.html', contexto)

def view_pregunta_nueva(request, cuest_id):
    try:
        cuestionario = Cuestionario.objects.get(pk=int(cuest_id))
    except Cuestionario.DoesNotExist:
        raise Http404
    if request.method == 'POST':
        form = PreguntaForm(request.POST)
        if form.is_valid():
            pregunta_nueva = form.save(commit=False) #no guarda a base de datos todavia (commit=false) hay que agragar pk de cuestionario
            pregunta_nueva.cuestionario = cuestionario
            maxnum=Pregunta.objects.all().filter(cuestionario=cuest_id).aggregate(Max('numero'))['numero__max']
            if maxnum:
                pregunta_nueva.numero=maxnum+1
            else:
                pregunta_nueva.numero=1
            pregunta_nueva.save()
            return HttpResponseRedirect(reverse(view_cuestionario, args=[cuestionario.pk]))
    form = PreguntaForm()

    contexto = {'form':form, 'cuestionario': cuestionario, 'breadcrumbs': breadcrumbs(cuestionario, nuevohijo=True)}
    contexto.update(csrf(request))
    return render_to_response(r'edicion_hipertextual/nueva_pregunta_edicion_hipertextual.html', contexto)

def view_pregunta_shift(request, preg_id, direccion):
    try:
        pregunta = Pregunta.objects.get(pk=int(preg_id))
    except Pregunta.DoesNotExist:
        raise Http404
    if direccion == "up":
        pregunta.shiftOrdenUp()
    elif direccion == "down":
        pregunta.shiftOrdenDown()
    return HttpResponseRedirect(reverse(view_cuestionario, args=[pregunta.cuestionario.pk]))

def view_pregunta_eliminar(request, preg_id):
    try:
        pregunta = Pregunta.objects.get(pk=preg_id)
    except:
        raise Http404
    pregunta.delete()
    return HttpResponseRedirect(reverse(view_cuestionario, args=[pregunta.cuestionario.pk]))


######################OPCION#######################
            
class OpcionForm(ModelForm):
    class Meta:
        model = Opcion
        fields = ('nombre','texto')

def view_opcion(request, opc_id):
    try:
        opcion = Opcion.objects.get(pk=int(opc_id))
    except Opcion.DoesNotExist:
        raise Http404
    if request.method == 'POST':
        form = OpcionForm(request.POST, instance=opcion)
        if form.is_valid():
            form.save()
    form = OpcionForm(instance = opcion)

    contexto = {'form':form, 'opcion': opcion, 'breadcrumbs': breadcrumbs(opcion), 'reglapreview': previewRegla(opcion.regla)}
    contexto.update(csrf(request))
    return render_to_response(r'edicion_hipertextual/opcion_edicion_hipertextual.html', contexto)


def view_opcion_nueva(request, preg_id):
    try:
        pregunta = Pregunta.objects.get(pk=int(preg_id))
    except Pregunta.DoesNotExist:
        raise Http404
    if request.method == 'POST':
        form = OpcionForm(request.POST)
        if form.is_valid():
            opcion_nueva = form.save(commit=False) #no guarda a base de datos todavia (commit=false) hay que agragar pk de pregunta
            opcion_nueva.pregunta = pregunta
            opcion_nueva.save()
            return HttpResponseRedirect(reverse(view_pregunta, args=[pregunta.pk]))

    form = OpcionForm()
    contexto = {'form':form, 'pregunta': pregunta, 'breadcrumbs': breadcrumbs(pregunta, nuevohijo=True)}
    contexto.update(csrf(request))
    return render_to_response(r'edicion_hipertextual/nueva_opcion_edicion_hipertextual.html', contexto)

def view_opcion_eliminar(request, opc_id):
    try:
        opcion = Opcion.objects.get(pk=opc_id)
    except:
        raise Http404
    opcion.delete()
    return HttpResponseRedirect(reverse(view_pregunta, args=[opcion.pregunta.pk]))

#######REGLA############

#retorna un diccionario con ('titulo', '<a href="">titulo</a>
def linkElementoDeCuestionario(elemento):
    e=elemento.getSubTipo()
    if isinstance(e, Pregunta):
        titulo = 'Pregunta'
        preview = e.texto
        url = reverse(view_pregunta, args=[e.pk])
    if isinstance(e, GrupoDePreguntas):
        titulo = 'GrupoDePreguntas'
        #url = reverse(view_grupodepreguntas, args=[e.pk])
    if isinstance(e, Opcion):
        titulo = 'Opcion'
        preview = e.texto
        url = reverse(view_opcion, args=[e.pk])
    if isinstance(e, GrupoDeOpciones):
        titulo='GrupoDeOpciones'
        #url = reverse(view_grupodeopciones, args=[e.pk])
    return {'titulo':titulo, 'link':'<a href="%s">%s</a>' % (url,preview)}

def view_regla(request, elem_id):
    elemento = ElementoDeCuestionario.objects.get(pk=elem_id).getSubTipo()
    link_elemento = linkElementoDeCuestionario(elemento)
    contexto = {'elemento':elemento, 'link_elemento':link_elemento,
                'convertbox': EBFConvertBoxRender(elemento),
                'breadcrumbs': breadcrumbs(elemento, regla=True),
                'maparegla': mapaRegla(elemento)}
    return render_to_response(r'edicion_hipertextual/regla_edicion_hipertextual.html', contexto)
    

def view_regla_nueva(request, elem_id,tipo):
    elemento= ElementoDeCuestionario.objects.get(pk=elem_id).getSubTipo()
    elemento.convertirRegla(tipo)
    return HttpResponseRedirect(reverse(view_regla, args=[elemento.pk]))
    

########################################################
######EBF
#################################

def EBFConvertBoxRender(padre, ebf=None):
    '''
    devuelve un diccionario {'label': LINK,
                             'links': [LINK_1,LINK_2,LINK_3],
                             deletelink: LINK}
    donde cada LINK es una dupla ('label','url') o None
    el parametro ebf es solo necesario para determinar el hijo de OperacionNaria
    '''
    
    if isinstance(padre,Negacion):
        if padre.der:
            ebf=padre.der.getSubTipoEBF()
    if isinstance(padre,ElementoDeCuestionario):
        if padre.regla:
            ebf=padre.regla.getSubTipoEBF()
    
    ebfcbr={'label':None,
            'links':[None,None,None],
            'deletelink': None}
    #return ebfcbr
    
    if ebf is None:
        if isinstance(padre,OperacionNaria):
            ebfcbr['links'][0]=('OperacionNaria',reverse(view_crear_operando_on, args=[padre.id, 'OperacionNaria']))
            ebfcbr['links'][1]=('Negacion',reverse(view_crear_operando_on, args=[padre.id, 'Negacion']))
            ebfcbr['links'][2]=('VariableLibre',reverse(view_crear_operando_on, args=[padre.id, 'VariableLibre']))
        if isinstance(padre,Negacion):
            ebfcbr['links'][0]=('OperacionNaria',reverse(view_crear_der_negacion, args=[padre.id, 'OperacionNaria']))
            ebfcbr['links'][1]=('Negacion',reverse(view_crear_der_negacion, args=[padre.id, 'Negacion']))
            ebfcbr['links'][2]=('VariableLibre',reverse(view_crear_der_negacion, args=[padre.id, 'VariableLibre']))
        if isinstance(padre,ElementoDeCuestionario):
            ebfcbr['links'][0]=('OperacionNaria',reverse(view_crear_regla_elem, args=[padre.id, 'OperacionNaria']))
            ebfcbr['links'][1]=('Negacion',reverse(view_crear_regla_elem, args=[padre.id, 'Negacion']))
            ebfcbr['links'][2]=('VariableLibre',reverse(view_crear_regla_elem, args=[padre.id, 'VariableLibre']))
    else:
        ebfcbr['label']=(ebf.nombre_de_clase, reverse(view_ebf, args=[ebf.pk]))
        if not isinstance(ebf,OperacionNaria):
            ebfcbr['links'][0]=('OperacionNaria',reverse(view_convertir_ebf, args=[ebf.id, 'OperacionNaria']))
        if not isinstance(ebf,Negacion):
            ebfcbr['links'][1]=('Negacion',reverse(view_convertir_ebf, args=[ebf.id, 'Negacion']))
        if not isinstance(ebf,VariableLibre):
            ebfcbr['links'][2]=('VariableLibre',reverse(view_convertir_ebf, args=[ebf.id, 'VariableLibre']))
            
        if isinstance(padre,OperacionNaria):
            ebfcbr['deletelink'] = ('(eliminar operando)', reverse(view_eliminar_operando, args=[ebf.pk]))
        if isinstance(padre,ElementoDeCuestionario):
            ebfcbr['deletelink'] = ('(eliminar regla)', reverse(view_eliminar_regla, args=[ebf.pk]))
    return ebfcbr
        
    
    
    

#linkPadreEBF genera un diccionario {'titulo': 'el_titulo', 'link': '<a href="el_link">preview</a>
def linkPadreEBF(ebf):
    #buscar en negaciones
    if Negacion.objects.filter(der=ebf.pk).exists():
        padre = Negacion.objects.get(der=ebf.pk)
        titulo = 'Negacion'
        url = reverse(view_ebf, args=[padre.pk])
        preview = 'Negacion'
    #buscar en operaciones binarias
    elif OperacionNaria.objects.filter(der=ebf.pk).exists():  #derecha
        padre = OperacionNaria.objects.get(der=ebf.pk)
        titulo = 'OperacionNaria'
        url = reverse(view_ebf, args=[padre.pk])
        preview = 'OperacionNaria'
    elif OperacionNaria.objects.filter(izq=ebf.pk).exists(): #izquierda
        padre = OperacionNaria.objects.get(izq=ebf.pk)
        titulo = 'OperacionNaria'
        url = reverse(view_ebf, args=[padre.pk])
        preview = 'OperacionNaria'
    #buscar en reglas
    elif ElementoDeCuestionario.objects.filter(regla=ebf.pk).exists():
        padre = ElementoDeCuestionario.objects.get(regla=ebf.pk)
        return linkElementoDeCuestionario(padre)
    else:
        raise ValueError("no se encontro un padre para la EBF %d" % ebf.id)
    return {'titulo':titulo, 'link':'<a href="%s">%s</a>' % (url,preview)}

def view_ebf(request, ebf_id):
    ebf=EBF.objects.get(pk=int(ebf_id)).getSubTipoEBF() #getSubTipoEBF() necesario para conseguir el subtipo final, y no el tipo EBF
    contexto = {'ebf':ebf, 'breadcrumbs': breadcrumbs(ebf), 'maparegla': mapaRegla(ebf)}
    if isinstance(ebf,Negacion):
        contexto.update({'convertbox': EBFConvertBoxRender(ebf)})
        #return HttpResponse(contexto['links_convertir'])
        return render_to_response(r'edicion_hipertextual/negacion_edicion_hipertextual.html',contexto)        
    if isinstance(ebf,OperacionNaria):
        if request.method == 'POST':
            form = OperacionNariaForm(request.POST, instance=ebf)
            if form.is_valid():
                form.save()
        form = OperacionNariaForm(instance=ebf)
        convertboxes = []
        #para cada operando de la OperacionNaria
        for operando in ebf.operandos.all():
            operando = operando.getSubTipoEBF()
            convertboxes.append(EBFConvertBoxRender(ebf, operando))
        #para el ultimo convertbox que servira para agregar un nuevo operando
        convertboxes.append(EBFConvertBoxRender(ebf))
        contexto.update({'convertboxes': convertboxes,
                            'form':form})
        contexto.update(csrf(request))
        return render_to_response(r'edicion_hipertextual/operacionnaria_edicion_hipertextual.html',contexto)
    if isinstance(ebf,VariableLibre):
        if request.method == 'POST':
            form = VariableLibreForm(ebf,request.POST)
            if form.is_valid():
                form.guardar()
        else:
            form = VariableLibreForm(ebf)
        contexto.update({'formvl': VariableLibreForm(ebf)})
        contexto.update(csrf(request))
        return render_to_response(r'edicion_hipertextual/variablelibre_edicion_hipertextual.html',contexto)

def view_convertir_ebf(request,ebf_id, nuevoTipo):
    ebf = EBF.objects.get(pk=ebf_id)
    padre = ebf.getPadre()
    if isinstance(padre,Negacion):
        padre.convertirDer(nuevoTipo)
        return HttpResponseRedirect(reverse(view_ebf,args=[padre.pk]))
    elif isinstance(padre,OperacionNaria):
        padre.convertirOperando(nuevoTipo,ebf.pk)
        return HttpResponseRedirect(reverse(view_ebf,args=[padre.pk]))
    elif isinstance(padre,ElementoDeCuestionario):
        padre.convertirRegla(nuevoTipo)
        return HttpResponseRedirect(reverse(view_regla,args=[padre.pk]))
        
def view_crear_der_negacion(request,neg_id,nuevoTipo):
    neg=Negacion.objects.get(pk=neg_id)
    neg.convertirDer(nuevoTipo)
    return HttpResponseRedirect(reverse(view_ebf, args=[neg_id]))

def view_crear_operando_on(request,on_id,nuevoTipo):
    on=OperacionNaria.objects.get(pk=on_id)
    on.convertirOperando(nuevoTipo)
    return HttpResponseRedirect(reverse(view_ebf,args=[on_id]))

def view_crear_regla_elem(request,elem_id,nuevoTipo):
    elem=ElementoDeCuestionario.objects.get(pk=elem_id)
    elem.convertirRegla(nuevoTipo)
    return HttpResponseRedirect(reverse(view_regla,args=[elem_id]))

def view_eliminar_regla(request,ebf_id):
    ebf=get_object_or_404(EBF, pk=ebf_id)
    elem = ebf.elementodecuestionario_set.get()
    ebf.delete()
    return HttpResponseRedirect(reverse(view_regla, args=[elem.pk]))

def view_eliminar_operando(request, ebf_id):
    ebf=get_object_or_404(EBF, pk=ebf_id)
    on = ebf.opn_set.get()
    ebf.delete()
    return HttpResponseRedirect(reverse(view_ebf, args=[on.pk]))

class OperacionNariaForm(ModelForm):
    class Meta:
        model = OperacionNaria
        fields = ('op',)


##############################################
########VARIABLE LIBRE
#################################################


class VariableLibreForm(forms.Form):
    vlfield = forms.ChoiceField(widget=forms.RadioSelect)
    instancia = None
    #ordenamiento: un par de listas con valores booleanos que indican si antes del choice en cuestion hay que poner \
    #    titulo (para cada linea) o
    #    indentacion al titulo (para las opciones)
    #generado en generarChoices
    #ordenamiento = None
    renglones=[]
    seleccionado=''

    def __init__(self, instance, data=None):
        super(VariableLibreForm,self).__init__(data)        
        if not isinstance(instance,VariableLibre):
            raise ValueError("instance no es VariableLibre")
        self.instancia=instance
        self.generarChoices()
        self.seleccionado = self.miCodif()
    
    def generarChoices(self):
        lista = []
        cuestionario = self.instancia.getCuestionarioPadre()
        #preguntas = Pregunta.objects.filter(cuestionario=cuestionario.pk)
        preguntas = self.instancia.getPreguntasValidas()
        camposBool = CampoBoolVolatil.objects.all()
        #lista.append( ('___', '(ninguno)') )
        #self.ordenamiento = {'titulo': [], 'indentacion': []}
        for campo in camposBool:
            if campo.nombre=='activado':
                activado_id=campo.pk
            if campo.nombre=='seleccionado':
                seleccionado_id=campo.pk
        self.renglones=[]
        for pregunta in preguntas:
            #self.ordenamiento['titulo'].append(True)
            #self.ordenamiento['indentacion'].append(False)
            lista.append( (str(pregunta.pk) + "_" + str(activado_id) , "%s(activado)" % pregunta.texto) )
            self.renglones.append( (pregunta.texto, str(pregunta.pk) + "_" + str(activado_id), None) )
            opciones = Opcion.objects.filter(pregunta=pregunta.pk)
            for opcion in opciones:
                #self.ordenamiento['indentacion'].append(True)
                #if campo.nombre=='activado':
                #    self.ordenamiento['titulo'].append(True)
                #else:
                #    self.ordenamiento['titulo'].append(False)
                lista.append( (str(opcion.pk) + "_" + str(activado_id) , "%s(activado)" % opcion.texto) )
                lista.append( (str(opcion.pk) + "_" + str(seleccionado_id) , "%s(seleccionado)" % opcion.texto) )
                self.renglones.append( (opcion.texto, str(opcion.pk) + "_" + str(activado_id), str(opcion.pk) + "_" + str(seleccionado_id)))
        self.fields['vlfield']._set_choices(lista)
        self.fields['vlfield'].initial = self.miCodif()
    
    def miCodif(self):
        if self.instancia.elemento_de_cuestionario is None or self.instancia.campo_bool_volatil is None:
            return '___'
        return str(self.instancia.elemento_de_cuestionario.pk) + '_' + str(self.instancia.campo_bool_volatil.pk)

    def guardar(self):
        dato = self.cleaned_data['vlfield']
        if dato[0] == '_':
            self.instancia.elemento_de_cuestionario = None
            self.instancia.campo_bool_volatil = None
        else:
            m = re.search(r'([0-9]+)_([0-9]+)', dato)
            id_elem = m.group(1)
            id_campo = m.group(2)
            elemento = ElementoDeCuestionario.objects.get(pk=id_elem)
            campobool = CampoBoolVolatil.objects.get(pk=id_campo)
            self.instancia.elemento_de_cuestionario = elemento
            self.instancia.campo_bool_volatil = campobool
        self.instancia.save()
        
    def asdchoices(self,p):
        return self.vlfield.choices[p]


############################
###Breadcrumbs
########################

#devuelve una lista de duplas (tag, url) en orden
#que representan el camino al objetivo. url puede ser None
#parametros
#  -objetivo: puede ser pregunta,opcion,cuestionario, ebf
#  -regla: booleano que indica si se trata de la regla de un elemento de cuestionario
#            (solo usada cuando objetivo es un ElementoDeCuestionario)
#  -nuevohijo: booleano que indica si se trata de la pantalla de creacion de:
#                    *nueva opcion cuando objetivo es pregunta
#                    *nueva pregunta cuando objetivo es cuestionario
def breadcrumbs(objetivo,regla=False,nuevohijo=False):
    if isinstance(objetivo, Pregunta):
        if nuevohijo:
            milink = ('Nueva Opcion', reverse(view_opcion_nueva, args=[objetivo.pk]))
            prevbc = breadcrumbs(objetivo)
        elif regla:
            milink = ('Regla', reverse(view_regla, args=[objetivo.pk]))
            prevbc = breadcrumbs(objetivo)
        else:
            milink = ('Pregunta', reverse(view_elementodecuestionario,args=[objetivo.pk]))
            prevbc = breadcrumbs(objetivo.cuestionario)
    elif isinstance(objetivo, Opcion):
        if regla:
            milink = ('Regla', reverse(view_regla, args=[objetivo.pk]))
            prevbc = breadcrumbs(objetivo)
        else:
            milink = ('Opcion', reverse(view_elementodecuestionario, args=[objetivo.pk]))
            prevbc = breadcrumbs(objetivo.pregunta)
    elif isinstance(objetivo, EBF):
        elemento_padre = objetivo.getElementoDeCuestionarioPadre()
        milink = ('Regla', reverse(view_ebf, args=[objetivo.pk]))
        prevbc= breadcrumbs(elemento_padre)
    elif isinstance(objetivo, Cuestionario):
        if nuevohijo:
            milink= ('Nueva Pregunta', reverse(view_pregunta_nueva, args=[objetivo.pk]))
            prevbc = breadcrumbs(objetivo)
        else:
            milink= ('Cuestionario', reverse(view_cuestionario, args=[objetivo.pk]))
            prevbc= [('Home', reverse(index)), ('Cuestionarios', reverse(view_lista_cuestionarios))]
    bc = prevbc
    bc.append(milink)
    return bc


###################################
#Mapa Regla
################################

#Devuelve una lista de triplas (tag,url,nivel, rangelvlup, rangelvldown) donde:
#    -tag es la etiqueta a mostrar
#    -url es la url (u don't say)
#    -nivel es el nivel dentro del arbol, siendo el nivel de la raiz (la regla) 0
#    -rangelvlup range con el numero de lvl up del nivel con respecto al anterior (abrir <ul> x ej)
#    -rangelvldown range con el numero de lvl down del siguiente con respecto al actual (x ej para </ul>) 

#     parametro e: puede ser un ElementoDeCuestionario o una EBF. Este elemento no tendra url

def mapaRegla(e):
    if isinstance(e,ElementoDeCuestionario):
        lista3tuplas= mapaReglaR(e)
    elif isinstance(e,EBF):
        elem=e.getElementoDeCuestionarioPadre()
        lista3tuplas= mapaReglaR(elem,e)
    else:
        raise ValueError('e es de tipo no valido')
    
    #agregar los rangelvlup y rangelvldown
    lista5tuplas=[]
    nivelanterior=0
    for tag,url,nivel in lista3tuplas:
        if nivel==nivelanterior: #solo el elemento root tendria que tener nivel 0
            lista5tuplas.append((tag,url,nivel,range(0),range(0)))
        elif nivel > nivelanterior:
            lista5tuplas.append((tag,url,nivel,range(nivel-nivelanterior),range(0)))
        elif nivel < nivelanterior:
            aux = lista5tuplas[-1]
            lista5tuplas[-1] = (aux[0],aux[1],aux[2],aux[3],range(nivelanterior-nivel))
            lista5tuplas.append((tag,url,nivel,range(0),range(0)))
        nivelanterior=nivel
    aux = lista5tuplas[-1]
    lista5tuplas[-1] = (aux[0],aux[1],aux[2],aux[3],range(nivelanterior))
    return lista5tuplas
    

def mapaReglaR(e,ebfposicion=None,nivel=0):
    '''
    e igual que mapaRegla... e puede ser None
    ebfposicion: es la ebf en la que se situa la vista... no tendra url. Si es None
                    significa que se situa en la raiz, y la raiz no tendra posicion
    '''
    if isinstance(e, EBF):
        e = e.getSubTipoEBF()
    
    if isinstance(e, ElementoDeCuestionario):
        tag='Regla'
        url= reverse(view_regla, args=[e.pk])
        below = mapaReglaR(e.regla,ebfposicion,nivel+1)
    elif isinstance(e, VariableLibre):
        tag='vl'
        url= reverse(view_ebf, args=[e.pk])
        below = []
    elif isinstance(e, Negacion):
        tag='neg'
        url=reverse(view_ebf, args=[e.pk])
        below = mapaReglaR(e.der, ebfposicion,nivel+1)
    elif isinstance(e, OperacionNaria):
        if e.op:
            tag = e.op.nombre
        else:
            tag='on'
        url=reverse(view_ebf, args=[e.pk])
        below=[]
        for operando in e.operandos.all():
            below.extend(mapaReglaR(operando,ebfposicion,nivel+1))
        else:
            below.extend(mapaReglaR(None,ebfposicion,nivel+1))
    elif e is None:
        tag='(vacio)'
        url=None
        below=[]
    else:
        raise ValueError("e es de tipo no valido")
    
    if e==ebfposicion or (ebfposicion is None and isinstance(e, ElementoDeCuestionario)):
        url=None
    
    mapa=[(tag,url,nivel)]
    mapa.extend(below)
    return mapa


def previewRegla(regla):
    if regla is None:
        return "(sin regla)"
    return previewEBF(regla)

def previewEBF(ebf):
    if ebf is None:
        return "___"
    ebf = ebf.getSubTipoEBF()
    previewstr=""
    if isinstance(ebf,OperacionNaria):
        if ebf.op:
            opstr=ebf.op.simbolo
        else:
            opstr="#"
        previewstr=previewstr+"("
        pri=True
        for operando in ebf.operandos.all():
            if not pri:
                previewstr=previewstr+" "+opstr+" "
            else:
                pri=False
            previewstr=previewstr+previewEBF(operando)
        if pri: #no hubo ningun operando
            previewstr = previewstr + previewEBF(None)
        previewstr=previewstr+")"
    elif isinstance(ebf,Negacion):
        previewstr="~"+previewEBF(ebf.der)
    elif isinstance(ebf,VariableLibre):
        if not ebf.elemento_de_cuestionario:
            previewstr=previewEBF(None)
        else:
            previewstr=ebf.elemento_de_cuestionario.nombre
        if ebf.campo_bool_volatil:
            previewstr=previewstr+"."+ebf.campo_bool_volatil.nombre
    else:
        raise ValueError("parametro no es una EBF valida")
    return previewstr

